package springinpractice.ch4.r4_3.web;

import java.util.logging.Logger;

import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.validation.Validator;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import springinpractice.ch4.r4_3.model.User;
import springinpractice.ch4.r4_3.service.DuplicateRegistrationException;
import springinpractice.ch4.r4_3.service.UserService;;

/*
 * Author       :       Willie Wheeler and John Wheeler
 * Book         :       'Spring In Practice' [Book written by Willie Wheeler and John Wheeler]
 */

@Controller
@RequestMapping("register/form.htm")
public class RegFormController {
	private static final String MA_USER = "user";
	
	private Validator validator;
	private UserService userService;
	
	@Autowired
	public void setValidator(Validator validator) {
		this.validator = validator;
	}
	
	@Autowired
	public void setUserService(UserService userService) {
		this.userService = userService;
	}
	
	@RequestMapping(method = RequestMethod.GET)
	public void form(Model model) {
		Logger.global.info("Serving initial form");
		model.addAttribute(MA_USER, new User());
	}
	
	@RequestMapping(method = RequestMethod.POST)
	public String form(
			@ModelAttribute(MA_USER) User user,
			BindingResult result) {
		
		Logger.global.info("Processing form submission");
		verifyBinding(result);
		validator.validate(user, result);
		
		try {
			userService.registerUserIfValid(user, !result.hasErrors());
		} catch (DuplicateRegistrationException dre) {
			if (dre.isUsernameTaken()) {
				result.rejectValue("username", "not.unique",
						new String[] { "Username" }, null);
			}
			if (dre.isEmailTaken()) {
				result.rejectValue("email", "not.unique");
			}
		}
		
		if (result.hasErrors()) {
			result.reject("form.problems");
			return "/register/form";
		}
		
		Logger.global.info("Processing user: " + user);
		return "redirect:confirm.htm";
	}
	
	@InitBinder
	public void initBinder(WebDataBinder binder) {
		Logger.global.info("Initializing binder");
		binder.setAllowedFields(new String[] { 
				"firstName", "lastName", "email",
				"username", "password", "passwordConfirmation",
				"marketingOk", "acceptTerms"
		});
	}		
	
	private void verifyBinding(BindingResult result) {
		Logger.global.info("Verifying binding");
		String[] suppressedFields = result.getSuppressedFields();
		if (suppressedFields.length > 0) {
			throw new RuntimeException("You've attempted to bind fields that haven't been allowed in initBinder(): " 
					+ StringUtils.join(suppressedFields, ", "));
		}
	}	
}
